/*
 * pattern.c
 *
 *  Created on: 19-05-2013
 *      Author: Artur Góralewski
 */

#include "pattern.h"

//function that creates the pattern
//its args are first - is number of elements in the pattern
//the rest of args are elements_of_pattern
pattern* create_pattern(const int amount_args, ...)
{
	if (amount_args > MAX_SIZE_OF_PATTERN)
		return NULL;
	
	pattern* new_pattern;
	new_pattern = (pattern*)malloc(sizeof(pattern));
	
	if (new_pattern == NULL)
	{
		printf("Przydział pamięci nie udał się\n");
		exit(EXIT_FAILURE);
	}
	
	if (amount_args == 0)
	{
	    new_pattern->pattern_type = READ_PATTERN;
	    new_pattern->first = NULL;
	    return new_pattern;
	}

	va_list args; //object that contains args
	va_start(args, amount_args); //initialization of object
	element_of_pattern *ptr1, elem = va_arg(args, element_of_pattern);
							//va_arg() - returns next element of args

	new_pattern->pattern_type = READ_PATTERN;
	new_pattern->first = (element_of_pattern*) malloc (sizeof(element_of_pattern));
	if(new_pattern->first == NULL)
	{
		printf("Przydział pamięci nie udał się\n");
		exit(EXIT_FAILURE);
	}

	if(elem.valid_data)	//if contains valid data
		new_pattern->first->data = elem.data;
	new_pattern->first->valid_data = elem.valid_data;
	new_pattern->first->comp_oper = elem.comp_oper;
	new_pattern->first->type = elem.type;
	new_pattern->first->next = NULL;

	ptr1 = new_pattern->first;
	int i = 0;
	for(i = 1; i < amount_args; i++)
	{
		 elem = va_arg(args, element_of_pattern);
		 ptr1->next = (element_of_pattern*) malloc (sizeof(element_of_pattern));
		 if(ptr1->next == NULL)
		 {
			printf("Przydział pamięci nie udał się\n");
	 		exit(EXIT_FAILURE);
		 }
		 ptr1 = ptr1->next;
		 if(elem.valid_data)  //if contains valid data
			 ptr1->data = elem.data;
		 ptr1->valid_data = elem.valid_data;
		 ptr1->comp_oper= elem.comp_oper;
		 ptr1->type = elem.type;
		 ptr1->next = NULL;
	}

	va_end(args); //releases dynamically allocated memory that maintains a list of arg

	return new_pattern;
}

//additional function that adds a element to the pattern
void add_elem_to_pattern (pattern *pat, const element_of_pattern elem)
{
    element_of_pattern *ptr, *add;

    add = (element_of_pattern*)malloc(sizeof(element_of_pattern));

    if(add == NULL)
    {
       printf("Przydział pamięci nie udał się\n");
       exit(EXIT_FAILURE);
    }

    if (elem.valid_data)	//if contains valid data
       add->data = elem.data;
   
    add->comp_oper = elem.comp_oper;
    add->type = elem.type;
    add->valid_data = elem.valid_data;
    add->next = NULL;
    
    ptr = pat->first;
    
    if (ptr == NULL) {
        // pattern empty
        pat->first = add;
    } else {
        while (ptr->next != NULL)
            ptr = ptr->next;
        ptr->next = add;
    }
}


//function that prints the pattern
void print_pattern(const pattern *pat)
{
    printf("\n## Wzorzec krotki:\n");
    element_of_pattern *ptr= pat->first;
    
    while( ptr != NULL )
      {
    	switch(ptr->type)
    	{
		case STRING:
			switch (ptr->comp_oper)
			{
			case (EQUAL):
				printf("# string: %s operator: ==\n", ptr->data._string);
				break;
			case (SMALLER):
				printf("# string: %s operator: <\n", ptr->data._string);
				break;
			case (NOT_LARGER):
				printf("# string: %s operator: <=\n", ptr->data._string);
				break;
			case (LARGER):
				printf("# string: %s operator: >\n", ptr->data._string);
				break;
			case (NOT_SMALLER):
				printf("# string: %s operator: >=\n", ptr->data._string);
				break;
			}
        		break;
		case FLOAT:
			switch (ptr->comp_oper) {
			case (EQUAL):
				printf("# float: %f operator: ==\n", ptr->data._float);
				break;
			case (SMALLER):
				printf("# float: %f operator: <\n", ptr->data._float);
				break;
			case (NOT_LARGER):
				printf("# float: %f operator: <=\n", ptr->data._float);
				break;
			case (LARGER):
				printf(" # float: %f operator: >\n", ptr->data._float);
				break;
			case (NOT_SMALLER):
				printf("# float: %f operator: >=\n", ptr->data._float);
				break;
			}
			break;
		case INTEGER:
			switch (ptr->comp_oper) {
			case (EQUAL):
				printf("# int: %d operator: ==\n", ptr->data._integer);
				break;
			case (SMALLER):
				printf("# int: %d operator: <\n", ptr->data._integer);
				break;
			case (NOT_LARGER):
				printf("# int: %d operator: <=\n", ptr->data._integer);
				break;
			case (LARGER):
				printf("# int: %d operator: >\n", ptr->data._integer);
				break;
			case (NOT_SMALLER):
				printf("# int: %d operator: >=\n", ptr->data._integer);
				break;
			}
			break;
    	}
      ptr = ptr->next;
      }
      printf("##\n");
}

//function that deletes the pattern
void delete_pattern(pattern *pat)
{
     element_of_pattern *ptr = pat->first;
     while( ptr != NULL )
       {
     	element_of_pattern *temp = ptr->next;
     	free(ptr);
     	ptr = temp;
       }
     free(pat);
}

//function that compare pattern with tuple
_Bool comparison(const pattern *pat, const tuple *tup)
{
if (pat == NULL || tup == NULL)
    return false;
element_of_pattern *patt = pat->first;
element_of_tuple *tupp = tup->first;
if(patt == NULL || tupp == NULL)
return false;
while( patt != NULL && tupp != NULL)
{
    switch(patt->type)
    {   
        case STRING:
	        if(tupp->type != STRING) return false;
	        if(!patt->valid_data) break;
	      	switch(patt->comp_oper)
	      			{
	      				case(EQUAL):
	      						if(strcmp(patt->data._string, tupp->data._string) != 0)
	      							return false;
	      						break;
	      				case(SMALLER):
     	    	  				if(strcmp(patt->data._string, tupp->data._string) >= 0)
     	    	  					return false;
     	    	  				break;
	      				case(NOT_LARGER):
							    if(strcmp(patt->data._string, tupp->data._string) > 0)
		     	    	  			return false;
		     	   				break;
	      				case(LARGER):
							    if(strcmp(patt->data._string, tupp->data._string) <= 0)
		     	    	  			return false;
		     	   				break;
	      				case(NOT_SMALLER):
							    if(strcmp(patt->data._string, tupp->data._string) < 0)
				     	   			return false;
			      				break;
	      			}
	      	break;
        case INTEGER:
        	if(tupp->type != INTEGER) return false;
        	 if(!patt->valid_data) break;
        	switch(patt->comp_oper)
	     		{
       	   	   	   	   	 case(EQUAL):
       	   	   	   	   		if(patt->data._integer != tupp->data._integer)
       	   	   	   	   			return false;
       	   	   	   	   	 	 break;
       	   	   	   	   	 case(SMALLER):
						    if(patt->data._integer <= tupp->data._integer)
     	       	      			return false;
     	  	   	   	   	 	 break;
       	   	   	   	   	 case(NOT_LARGER):
						    if(patt->data._integer < tupp->data._integer)
							    return false;
		     	  	   	   	 break;
       	   	   	   	   	 case(LARGER):
						    if(patt->data._integer >= tupp->data._integer)
		     	       			return false;
		       	   	   	 	 break;
       	   	   	   	   	 case(NOT_SMALLER):
						    if(patt->data._integer > tupp->data._integer)
		     	      			return false;
		       	   	   	 	 break;
	     		}
        	break;
        case FLOAT:
	      if(tupp->type != FLOAT) return false;
	      	  if(!patt->valid_data) break;
        switch (patt->comp_oper)
        {
            case(EQUAL):
		        return false;
            case (SMALLER):
                if (patt->data._float <= tupp->data._float)
	                return false;
                break;
            case (NOT_LARGER):
                if (patt->data._float < tupp->data._float)
	                return false;
                break;
            case (LARGER):
                if (patt->data._float >= tupp->data._float)
	                return false;
                break;
            case (NOT_SMALLER):
                if (patt->data._float > tupp->data._float)
	                return false;
                break;
        }
    }
    patt = patt->next;
    tupp = tupp->next;
}

if (patt == NULL && tupp == NULL)
    return true;
else
    return false; // rozna liczba argumentow
}


